package orch

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/hashicorp/hcl/v2"
	"github.com/ihaiker/tfwrapper/internal/config"
	"github.com/ihaiker/tfwrapper/internal/errors"
	"github.com/ihaiker/tfwrapper/internal/hclfns"
	"github.com/ihaiker/tfwrapper/internal/shells"
	"github.com/ihaiker/tfwrapper/internal/util"
	"github.com/sirupsen/logrus"
	"os"
	"path"
	"path/filepath"
	"strconv"
)

func runBeforeHooks(running config.Running, args []string, hooks []config.Hook) hcl.Diagnostics {
	for _, hook := range hooks {
		if !util.Contain(hook.Commands, args[0]) {
			continue
		}
		cmd := shells.New(hook.Execute[0], hook.Execute[1:]...)
		if hook.WorkingDir != nil && *hook.WorkingDir != "" {
			cmd.WorkingDir(*hook.WorkingDir)
		} else {
			cmd.WorkingDir(running.WorkingDir)
		}
		if !hook.Quiet {
			cmd.WithWriter(os.Stderr)
		}
		logrus.Infof("run hook %s before %s",
			color.HiGreenString(hook.Name), color.HiGreenString(args[0]))
		if err := cmd.Run(); err != nil {
			if util.Bool(hook.RunOnError) {
				logrus.Errorf("run hook %s error %s", color.HiRedString(hook.Name), err)
			} else {
				return errors.Diagnostics("run hook error", err)
			}
		}
	}
	return nil
}

func runAfterHooks(terraformCommand error, running config.Running, args []string, hooks []config.Hook) hcl.Diagnostics {
	for _, hook := range hooks {
		if !util.Contain(hook.Commands, args[0]) {
			continue
		}
		if terraformCommand != nil && !util.Bool(hook.RunOnError) {
			logrus.Debugf("skip run hook %s after %s", color.HiGreenString(hook.Name), color.HiGreenString(args[0]))
			continue
		}

		cmd := shells.New(hook.Execute[0], hook.Execute[1:]...)
		if hook.WorkingDir != nil && *hook.WorkingDir != "" {
			cmd.WorkingDir(*hook.WorkingDir)
		} else {
			cmd.WorkingDir(running.WorkingDir)
		}
		if !hook.Quiet {
			cmd.WithWriter(os.Stderr)
		}
		logrus.Infof("run hook %s after %s",
			color.HiGreenString(hook.Name), color.HiGreenString(args[0]))
		if err := cmd.Run(); err != nil {
			if util.Bool(hook.RunOnError) {
				logrus.Errorf("run hook %s error %s", color.HiRedString(hook.Name), err)
			} else {
				return errors.Diagnostics("run hook error", err)
			}
		}
	}
	return nil
}

func runTerraformCommand(running config.Running, args []string) (string, hcl.Diagnostics) {
	if diags := runBeforeHooks(running, args, running.Terraform.BeforeHooks); util.HasErrors(diags) {
		return "", diags
	}

	cliArgs := make([]string, 0)
	cliEnvs := make(map[string]string, 0)

	//TOME 不支持中途输入，如果有未设置的参数将直接报错
	if util.Contain(hclfns.TerraformCommandsNeedInput, args[0]) {
		cliArgs = append(cliArgs, "-input=false")
	}
	//是否需要并发参数
	if util.Contain(hclfns.TerraformCommandsNeedParallelism, args[0]) && running.Parallelism != nil {
		cliArgs = append(cliArgs, "-parallelism", strconv.Itoa(int(*running.Parallelism)))
	}

	for _, extraArguments := range running.Terraform.ExtraArgs {
		if !util.Contain(extraArguments.Commands, args[0]) {
			continue
		}

		if extraArguments.Arguments != nil {
			cliArgs = append(cliArgs, *extraArguments.Arguments...)
		}

		if extraArguments.EnvVars != nil {
			for k, v := range *extraArguments.EnvVars {
				cliEnvs[k] = v
			}
		}

		if extraArguments.RequiredVarFiles != nil {
			for _, v := range *extraArguments.RequiredVarFiles {
				cliArgs = append(cliArgs, "-var-file", v)
			}
		}

		if extraArguments.OptionalVarFiles != nil {
			for _, v := range *extraArguments.OptionalVarFiles {
				varFilename := v
				if !filepath.IsAbs(v) {
					varFilename = filepath.Join(running.WorkingDir, v)
				}
				if !util.Exists(varFilename) {
					logrus.Debugf("-var-file %s not exists", varFilename)
					continue
				}
				cliArgs = append(cliArgs, "-var-file", varFilename)
			}
		}
	}

	terraformArgs := append(args, cliArgs...)
	cmd := shells.Terraform(running.GetTerraformBinary(), terraformArgs...)
	moduleAbsDir := path.Join(running.WorkingDir, running.ModuleDir)
	cmd.WorkingDir(moduleAbsDir)

	//是否需要输入
	if util.Contain(hclfns.TerraformCommandsNeedVars, args[0]) {
		for key, value := range running.Inputs {
			envValue := util.CtyValueToVarValue(value)
			cmd.Env(fmt.Sprintf("TF_VAR_%s", key), envValue)
		}
	}

	if util.Contain(hclfns.TerraformCommandsNeedStdOutput, args[0]) {
		cmd.WithWriter(os.Stdout)
	}

	stdout, _, err := cmd.RunWithOutput()

	diags := runAfterHooks(err, running, args, running.Terraform.AfterHooks)
	if err != nil {
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Terraform init error",
			Detail:   "run terraform command error",
		})
	}
	return stdout, diags
}
